Activity 生命周期

生命周期是系统在 Activity 状态变化时回调的一组方法。重点不是背顺序,而是搞清三件事:
每个回调对应什么状态、这个时机能做什么 / 不能做什么、哪个回调并不保证被调用。

1. 状态转换全景

graph TD
    A[onCreate] --> B[onStart]
    B --> C[onResume]
    C -- 失去焦点 --> D[onPause]
    D -- 重新获得焦点 --> C
    D -- 完全不可见 --> E[onStop]
    E -- 重新可见 --> F[onRestart]
    F --> B
    E -- 销毁 --> G[onDestroy]
    G -. 配置变更后重建 .-> A

四种状态

状态 对应回调 实例存活 可见 可交互
Resumed(运行) onResume ✅ ✅ ✅
Paused(暂停) onPause ✅ 可能部分可见 ❌
Stopped(停止) onStop ✅ ❌ ❌
Destroyed(销毁) onDestroy ❌ ❌ ❌

两个容易记错的点:

2. 七个回调

onCreate

onStart

onResume

onPause

onStop

onRestart

onDestroy

3. 常见场景的回调顺序

首次启动

onCreate → onStart → onResume

A 启动 B(B 全屏不透明)

A.onPause → B.onCreate → B.onStart → B.onResume → A.onStop

A 的 onStop 在 B 完全展示之后才执行,所以 A 会短暂停留在 Paused —— 这是正常现象,不是卡顿。

B 返回 A

B.onPause → A.onRestart → A.onStart → A.onResume → B.onStop → B.onDestroy

B 是 Dialog / 透明主题的 Activity

A.onPause → B.onCreate → B.onStart → B.onResume     # A 只 Pause,不 Stop(A 仍然可见)
B.onPause → A.onResume → B.onStop → B.onDestroy

按 Home 键 / 切到其他 App

onPause → onStop(实例还在内存里,没有销毁);回来时 onRestart → onStart → onResume。

锁屏 / 息屏

onPause → onStop;解锁后 onRestart → onStart → onResume。

屏幕旋转(未处理 configChanges)

onPause → onStop → onDestroy → onCreate → onStart → onRestoreInstanceState → onResume

重建时 onCreate 的 savedInstanceState 不为 null。

配置变更但不想重建

Manifest 里声明 android:configChanges="orientation|screenSize|keyboardHidden",系统只回调 onConfigurationChanged()。
代价是不会重新加载布局,横竖屏差异要自己处理 —— 但绕过重建通常比修重建的坑更省事。

进程被杀后恢复

onCreate(savedInstanceState != null) → onStart → onRestoreInstanceState → onResume

数据来自系统保存的 Bundle,不是 ViewModel —— ViewModel 已经随进程一起消失了。

App A 在前台时启动 App B

跨 App 跳转不会共享任务栈,但回调顺序与"Activity 跳 Activity"完全一致,只是分属两个进程:

A.onPause → (B 进程启动 / Application.onCreate)→ B.onCreate → B.onStart → B.onResume → A.onStop

由此可以推出两个结论:

4. 状态保存与恢复

onSaveInstanceState(Bundle)

onRestoreInstanceState(Bundle)

ViewModel 为什么能扛住旋转

三者怎么选

需求 用什么
转屏后保留内存中的复杂对象 ViewModel
进程被杀后恢复页面状态 onSaveInstanceState / SavedStateHandle
永久保存用户数据 SharedPreferences / DataStore / 数据库

5. 常见坑

  1. 在 onCreate / onStart 里取 View 宽高:一定为 0,用 View.post、doOnLayout 或 OnGlobalLayoutListener
  2. 把保存数据只放在 onDestroy:进程被杀时不执行,数据直接丢
  3. 在 onPause 里做耗时操作:卡住下一个页面的显示
  4. onPause 释放相机、onResume 立刻重开:页面切换时时序冲突会导致预览黑屏,建议放到 onStop / onStart 或加延迟
  5. 用静态变量 / 单例 / 非静态 Handler 持有 Activity:生命周期不对等 → 内存泄漏(用 WeakReference 或 applicationContext)
  6. 用 isFinishing() 判断销毁原因:配置变更时 onDestroy 也会走,但 isFinishing() 是 false,要配合 isChangingConfigurations()
  7. 把请求权限 / 弹 Dialog / 跳转放在 onResume:打断用户;Android 10+ 后台启动 Activity 受限,很容易被系统静默拦截
  8. 监听注册用 onCreate / onDestroy 配对:应该用 onStart / onStop 或 onResume / onPause,否则不可见时也在白耗资源
  9. 以为多窗口下失去焦点会走 onStop:多窗口里 Activity 仍可见,不会 onStop;Android 10(multi-resume)后连 onPause 都未必回调,判断"我是不是最上层"要用 onTopResumedActivityChanged(API 29+)

6. 与 Fragment / 应用前后台的关系

7. 一句话速查

回调 时机 关键词
onCreate 实例创建 只初始化一次、读 savedInstanceState、别耗时
onStart 可见 注册监听
onResume 可交互 独占资源(相机 / 传感器 / 动画)
onPause 失去焦点 必须快、释放轻量资源
onStop 完全不可见 可能被杀、在这里保存数据
onRestart 再次可见之前 只有从 Stop 回来才走
onDestroy 销毁之前 不一定被调用、isFinishing() 区分原因